﻿/*
 * copyright (c) 2009 hvbird
 *
 * This file is part of tdlib.
 *
 * tdlib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * tdlib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */


using System;
using System.Xml;
using System.Data;
using System.Text;
using System.Collections;
using System.Data.SqlClient;

namespace TDLib.Xml
{

    public class XMLHelper
    {
        #region 私有函数
        /// <summary>
        /// 从SelectXML（查询XML标准格式）中得到关键字段字符串
        /// </summary>
        /// <param name="xmlSelect">符合查询XML标准格式的XML文档</param>
        /// <returns>返回要查找的关键字段的字符串，每个关键字段用","隔开</returns>
        private static string GetStrKey(XmlDocument xmlSelect)
        {
            XmlNode xmlSechemaNode = xmlSelect.SelectSingleNode(".//SCHEMA");
            XmlAttribute keyAttr = xmlSechemaNode.Attributes["key"];
            MCSException.TrueThrow((keyAttr == null), "没有关键字！");

            string strKey = keyAttr.Value;
            MCSException.TrueThrow((strKey == string.Empty), "没有关键字！");

            return strKey;
        }

        /// <summary>
        /// 从SelectXML（查询XML标准格式）中得到要返回的最多记录条数
        /// </summary>
        /// <param name="xmlSelect">符合查询XML标准格式的XML文档</param>
        /// <returns>一个整数</returns>
        private static int GetMaxCount(XmlDocument xmlSelect)
        {
            int nMaxCount = 100;

            XmlNode xmlSechemaNode = xmlSelect.SelectSingleNode(".//SCHEMA");
            XmlAttribute keyAttr = xmlSechemaNode.Attributes["maxcount"];
            if (keyAttr != null && keyAttr.Value != string.Empty)
            {
                nMaxCount = int.Parse(keyAttr.Value);
            }

            return nMaxCount;
        }
        #endregion


        /// <summary>
        /// 从只包含关键字段的IDataReader中，读出关键字段的值，保存到新的XML中
        /// </summary>
        /// <param name="dataRdOfKey">只包含关键字段的IDataReader</param>
        /// <param name="nCount">要返回的关键字段的组个数</param>
        /// <returns>返回包含KEYVALU域的XML,组关键字间用";"隔开，组关键字段间关键字间用","隔开</returns>
        public static XmlDocument GetKeyValueXml(IDataReader dataRdOfKey, int nCount)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml("<DataSet/>");

            XmlElement root = xmlDoc.DocumentElement;

            string strColumnValue = string.Empty;
            StringBuilder strBKeyValue = new StringBuilder(1024);

            int nRow = 0;
            int nColumn = dataRdOfKey.FieldCount;


            //添加KEYVALUE节点
            while (dataRdOfKey.Read())
            {
                if (nRow > 0)
                    strBKeyValue.Append(";"); //每组关键字用";"隔开				

                for (int n = 0; n < nColumn; n++)
                {
                    if (n > 0)
                        strBKeyValue.Append(","); //每组内的各个关键字用","隔开 				

                    if (dataRdOfKey[n].GetType().ToString() == "System.DateTime")
                    {
                        strColumnValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", dataRdOfKey[n]);
                    }
                    else
                        strColumnValue = dataRdOfKey[n].ToString();

                    strBKeyValue.Append(strColumnValue);

                }

                nRow++;

                if (nRow == nCount)
                    break;
            }

            dataRdOfKey.Close();

            XmlNode keyValueNode = AppendNode(xmlDoc, root, "KEYVALUE", strBKeyValue.ToString());

            return xmlDoc;
        }



        #region 由DataSet生成XML ,可以解决字段中的NULL值在XML文档中不显示问题

        /// <summary>
        /// 由DataSet生成XML，可以解决字段中的NULL值在XML文档中不显示问题
        /// </summary>
        /// <param name="dataSet">标准的DataSet</param>
        /// <returns>返回符合由DataSet.GetXml()生成XML格式的XML文档</returns>
        public static XmlDocument GetXmlDoc(DataSet dataSet)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml("<DataSet/>");

            XmlElement root = xmlDoc.DocumentElement;

            foreach (DataTable dataTable in dataSet.Tables)
            {
                foreach (DataRow dataRow in dataTable.Rows)
                {
                    XmlNode xmlTableNode = AppendNode(xmlDoc, root, "Table");

                    foreach (DataColumn dataColumn in dataTable.Columns)
                    {
                        string strColumnValue = string.Empty;

                        if (dataRow[dataColumn] != null)
                        {
                            if (dataColumn.DataType.ToString() == "System.DateTime")
                                strColumnValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", dataRow[dataColumn]);
                            else
                                strColumnValue = dataRow[dataColumn].ToString();
                        }

                        XmlNode xmlColumnNode = AppendNode(xmlDoc, xmlTableNode, dataColumn.ColumnName, strColumnValue);

                    }
                }
            }

            return xmlDoc;
        }

        /// <summary>
        /// 由DataSet生成XML，可以解决字段中的NULL值在XML文档中不显示问题
        /// 此函数没有返回值
        /// </summary>
        /// <param name="xmlDoc">符合由DataSet.GetXml()生成XML格式的XML文档</param>
        /// <param name="dataSet">标准的DataSet</param>
        public static void GetXmlDoc(XmlDocument xmlDoc, DataSet dataSet)
        {
            xmlDoc.LoadXml(GetXmlDoc(dataSet).InnerXml);
        }

        #endregion

        #region 由IDataReader生成XML

        /// <summary>
        /// 由IDataReader生成XML
        /// </summary>
        /// <param name="dataReader">标准的IDataReader</param>
        /// <returns>返回符合由DataSet.GetXml()生成XML格式的XML文档</returns>
        public static XmlDocument GetXmlDoc(IDataReader dataReader)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml("<DataSet/>");

            XmlElement root = xmlDoc.DocumentElement;

            int nColumn = dataReader.FieldCount;

            while (dataReader.Read())
            {
                XmlNode xmlTableNode = AppendNode(xmlDoc, root, "Table");

                for (int n = 0; n < nColumn; n++)
                {
                    string strColumnValue = string.Empty;

                    if (dataReader[n] != null)
                    {
                        if (dataReader[n].GetType().ToString() == "System.DateTime")
                        {
                            strColumnValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", dataReader[n]);
                        }
                        else
                            strColumnValue = dataReader[n].ToString();
                    }

                    XmlNode xmlColumnNode = AppendNode(xmlDoc, xmlTableNode, dataReader.GetName(n), strColumnValue);
                }
            }

            dataReader.Close();

            return xmlDoc;
        }


        /// <summary>
        ///  由IDataReader生成XML,生成的XML存放在参数xmlDoc中
        /// </summary>
        /// <param name="xmlDoc">用来存放新生成XML文档</param>
        /// <param name="dataReader">标准的DdataReader</param>
        public static void GetXmlDoc(XmlDocument xmlDoc, IDataReader dataReader)
        {
            xmlDoc.LoadXml(GetXmlDoc(dataReader).InnerXml);
        }

        #endregion

        #region 与XML文档相关的辅助函数
        /// <summary>
        /// 建立一个Dom对象，并且可以初始化文档
        /// </summary>
        /// <param name="strXML">XML内容</param>
        /// <returns>XmlDocument对象</returns>
        public static XmlDocument CreateDomDocument(string strXML)
        {
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.LoadXml(strXML);

            return xmlDoc;
        }

        /// <summary>
        /// 在root节点下面添加一个子节点
        /// </summary>
        /// <param name="xmlDoc">文档对象</param>
        /// <param name="root">根节点</param>
        /// <param name="strNodeName">子节点名称</param>
        /// <returns>子节点对象</returns>
        public static XmlNode AppendNode(XmlDocument xmlDoc, XmlNode root, string strNodeName)
        {
            XmlNode node = xmlDoc.CreateNode(System.Xml.XmlNodeType.Element, strNodeName, "");

            root.AppendChild(node);

            return node;
        }

        /// <summary>
        /// 在root节点下面添加一个子节点
        /// </summary>
        /// <param name="xmlDoc">文档对象</param>
        /// <param name="root">根节点</param>
        /// <param name="strNodeName">子节点名称</param>
        /// <param name="strNodeText">子节点的内容</param>
        /// <returns>子节点对象</returns>
        public static XmlNode AppendNode(XmlDocument xmlDoc, XmlNode root, string strNodeName, string strNodeText)
        {
            XmlNode node = AppendNode(xmlDoc, root, strNodeName);
            if (strNodeText != string.Empty)
                node.InnerText = strNodeText;

            return node;
        }


        /// <summary>
        /// 为某一个节点添加一个属性
        /// </summary>
        /// <param name="xmlDoc">文档对象</param>
        /// <param name="node">节点</param>
        /// <param name="strAttrName">属性名称</param>
        /// <returns>属性对象</returns>
        public static XmlAttribute AppendAttr(XmlDocument xmlDoc, XmlNode node, string strAttrName)
        {
            XmlAttribute attr = xmlDoc.CreateAttribute(strAttrName);

            node.Attributes.SetNamedItem(attr);

            return attr;
        }

        /// <summary>
        /// 为某一个节点添加一个属性
        /// </summary>
        /// <param name="xmlDoc">文档对象</param>
        /// <param name="node">节点</param>
        /// <param name="strAttrName">属性名称</param>
        /// <param name="strValue">属性内容</param>
        /// <returns>属性对象</returns>
        public static XmlAttribute AppendAttr(XmlDocument xmlDoc, XmlNode node, string strAttrName, string strValue)
        {
            XmlAttribute attr = AppendAttr(xmlDoc, node, strAttrName);

            attr.Value = strValue;

            return attr;
        }

        #endregion

        #region 查询Key

        /// <summary>
        ///从根结点中取出参数 
        /// </summary>
        /// <param name="xmlNode">属性所在节点</param>
        /// <param name="strAttr">属性名</param>
        /// <returns></returns>
        public static string GetParamFromXml(XmlNode xmlNode, string strAttr)
        {
            string sParam = string.Empty;

            XmlAttribute xmlAttr = xmlNode.Attributes[strAttr];

            if (xmlAttr != null)
            {
                sParam = xmlAttr.Value.ToString();
            }
            return sParam;
        }

        /// <summary>
        /// 从当前查询的key中找到一串keyvalue
        /// </summary>
        /// <param name="xmlDoc">由Key值的xmlDoc</param>
        /// <param name="iCount">个数</param>
        /// <returns></returns>
        public static XmlDocument CutKeyFromKeyXml(XmlDocument xmlDoc, int iCount)
        {
            string[] strKeyValueArray;
            XmlDocument xmlKeyDoc = new XmlDocument(); ;
            string strKey = string.Empty;
            XmlNode xmlNode = xmlDoc.SelectSingleNode(".//KEYVALUE");
            if (xmlNode != null)
            {
                strKeyValueArray = xmlNode.InnerText.Split(';');
                if (strKeyValueArray.Length < iCount)
                    xmlKeyDoc = xmlDoc;
                else
                {
                    for (int i = 0; i < iCount; i++)
                    {
                        if (i == 0)
                            strKey += strKeyValueArray[i].ToString();
                        else
                            strKey += ";" + strKeyValueArray[i].ToString();
                    }
                    xmlKeyDoc.LoadXml(xmlDoc.InnerXml);
                    xmlKeyDoc.SelectSingleNode(".//KEYVALUE").InnerText = strKey;

                }
            }
            return xmlKeyDoc;
        }
        /// <summary>
        /// 从xml文档中取出key和keyvalue，组成一个字符串
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <returns></returns>
        public static string GetKeyByXml(XmlDocument xmlDoc)
        {
            StringBuilder strBd = new StringBuilder(1024);
            XmlNode xmlNode = xmlDoc.SelectSingleNode(".//KEY");

            string[] strKeyArray = xmlNode.InnerText.Split(',');

            xmlNode = xmlDoc.SelectSingleNode(".//KEYVALUE");

            if (xmlNode.InnerText == "") return "";

            string[] strKeyValueArray = xmlNode.InnerText.Split(';');

            strBd.Append("(");

            if (strKeyArray.Length == 1)
            {
                strBd.Append(strKeyArray[0].ToString());

                strBd.Append(" IN (");

                for (int i = 0; i < strKeyValueArray.Length; i++)
                {
                    if (i > 0)
                        strBd.Append(",");

                    strBd.Append("'");
                    strBd.Append(strKeyValueArray[i].ToString());
                    strBd.Append("'");

                }
                strBd.Append(")");
            }
            else
            {
                for (int i = 0; i < strKeyValueArray.Length; i++)
                {
                    string[] sMulKeyArray = strKeyValueArray[i].Split(',');

                    if (i > 0)
                        strBd.Append(" OR ");

                    strBd.Append("(");

                    for (int j = 0; j < strKeyArray.Length; j++)
                    {
                        if (j > 0)
                            strBd.Append(" AND ");
                        strBd.Append("(");
                        strBd.Append(strKeyArray[j]);
                        strBd.Append(" = '");
                        strBd.Append(sMulKeyArray[j]);
                        strBd.Append("')");
                    }
                    strBd.Append(")");
                }

            }
            strBd.Append(")");

            return strBd.ToString();
        }
        #endregion

    }

}
